
export interface OpType {
    zIndex?: number; // 层级，默认1211
    maskColor?: string; // 遮罩颜色
    body?: any; // 要插入的dom, 默认的为body，注意，传入undefined也会使用的默认值，但传入null时将报错
    startZoom?: number; // 初始化的缩放级别
    minZoom?: number; // 最小的缩放级别
    maxZoom?: number; // 最大的缩放级别
    isImgClose?: boolean; // 开启点击图片关闭
    isMaskClose?: boolean; // 开启点击遮罩关闭，开启遮罩移动（isMaskMove）后会跟随isImgClose的设置
    isOperation?: boolean; // 是否显示操作按钮
    isMaskWheel?: boolean; // 开启遮罩缩放
    isMaskMove?: boolean; // 开启遮罩移动
    tipTime?: number;
    backCall?: () => void; // 关闭的回调
    showCall?: () => void; // 显示的回调
}
export default class YYZIMG {
    t: number;
    l: number;
    w: number;
    h: number;
    rotate: number;
    zoom: number;
    box: any;
    box_w: number;
    box_h: number;
    img_w: number;
    img_h: number;
    url: string;
    op: any;
    canvasImg: any;
    ctx: any;
    body_overflow: any;
    isShow: any;
    // 构造方法
    constructor(url: string, op?: OpType) {
        this.t = 0;
        this.l = 0;
        this.w = 0;
        this.h = 0;
        this.rotate = 0;
        this.zoom = 1;
        this.img_w = 0;
        this.img_h = 0;
        this.box_w = 0;
        this.box_h = 0;
        this.url = url;
        this.isShow = false;
        this.op = {};

        const defaultOp = {
            zIndex: 1211,
            maskColor: "rgba(0,0,0,0.2)",
            body: document.body,
            startZoom: 1,
            minZoom: 0.1,
            maxZoom: 20,
            isImgClose: false,
            isMaskClose: true,
            isOperation: true,
            isMaskWheel: false, // 开启遮罩缩放
            isMaskMove: false, // 开启遮罩移动
            tipTime: 300, // 开启遮罩移动
        } as OpType;
        if (!op) op = {};
        for (const key in defaultOp) {
            this.op[key] =
                // @ts-ignore
                typeof op[key] == "undefined" ? defaultOp[key] : op[key];
        }
        if (!this.op.body) {
            console.error("传入的dom为空！");
            return;
        }
        // 自定义的body
        if (document.body != this.op.body) {
            console.log(this.op.body);

            if (typeof this.op.body == "string") {
                this.op.body = document.querySelector(this.op.body);
            }
            if (
                !this.op.body.style.position ||
                this.op.body.style.position == "static"
            ) {
                // console.error("你须要把body的position设置为absolute、fixed、relative");
                this.op.body.style.position = "relative";
            }
            this.op.body.style.overflow = "hidden"; // 防止溢出
        }

        this.body_overflow = document.body.style.overflow;
    }
    // 显示
    show() {
        if (this.isShow) {
            return;
        }
        this.isShow = true;
        document.body.style.overflow = "hidden";

        this.box = document.createElement("div"); //1、创建元素
        this.box.style.setProperty("--time", "0.3s");
        this.box.className = "yyz-iv";
        this.box.style.zIndex = this.op.zIndex;
        this.box.style.background = "transparent"; //背景先设置透明, 等一下来个动画
        this.box.style.opacity = 0;
        // 记录宽高
        this.box_h = this.op.body.offsetHeight;
        this.box_w = this.op.body.offsetWidth;
        if (document.body == this.op.body) {
            this.box_w =
                document.documentElement.clientWidth ||
                document.body.clientWidth;
            this.box_h =
                document.documentElement.clientHeight ||
                document.body.clientHeight;
            this.box.style.position = "fixed";
        }

        let img_box = document.createElement("div");
        img_box.className = "yyz-iv_img-box";
        this.box.appendChild(img_box);
        this.canvasImg = document.createElement("img");
        this.canvasImg.className = "yyz-iv_img";
        this.canvasImg.draggable = false;
        img_box.appendChild(this.canvasImg);
        this.canvasImg.onload = () => {
            this.zoom = this.op.startZoom;
            this.rotate = 0;
            //判断那一边是长边
            this.img_h = this.canvasImg.height;
            this.img_w = this.canvasImg.width;
            if (this.img_w / this.img_h > this.box_w / this.box_h) {
                this.w = this.zoom * this.box_w;
                this.h = this.w * (this.img_h / this.img_w);
                this.l = (this.box_w - this.box_w * this.zoom) / 2;
                this.t =
                    (this.box_h -
                        this.zoom * this.box_w * (this.img_h / this.img_w)) /
                    2;
            } else {
                this.h = this.zoom * this.box_h; // 高度充满
                this.w = this.h * (this.img_w / this.img_h);
                this.t = (this.box_h - this.box_h * this.zoom) / 2;
                this.l =
                    (this.box_w -
                        this.box_h * this.zoom * (this.img_w / this.img_h)) /
                    2;
            }
            this.upImgPosition();
        };

        this.op.body.appendChild(this.box);
        this.canvasImg.src = this.url;
        this.canvasEventsInit();
        setTimeout(() => {
            this.box.style.background = this.op.maskColor; //背景先设置透明, 等一下来个动画
            this.box.style.opacity = 1;
        }, 1);
        if (this.op.isOperation) this.addOperationButton();
        if (this.op.showCall) this.op.showCall();
        return this;
    }
    // 隐藏
    close() {
        this.box.style.setProperty("--time", "0.1s");
        console.log("隐藏");
        this.box.style.opacity = 0;
        setTimeout(() => {
            this.op.body.removeChild(this.box);
            document.body.style.overflow = this.body_overflow;
            this.isShow = false;
            if (this.op.backCall) this.op.backCall();
        }, 200);
        // 还原
    }
    // 刷新位置
    private upImgPosition(dh?: boolean) {
        if (this.img_w / this.img_h > this.box_w / this.box_h) {
            this.w = this.zoom * this.box_w; // 宽度充满
            this.h = this.w * (this.img_h / this.img_w);
        } else {
            this.h = this.zoom * this.box_h; // 高度充满
            this.w = this.h * (this.img_w / this.img_h);
        }
        if (dh) {
            this.canvasImg.style.setProperty("--img-time", "0.2s");
        }
        this.canvasImg.style.transform = `rotate(${this.rotate}deg)`;
        this.canvasImg.style.width = this.w + "px";
        this.canvasImg.style.height = this.h + "px";
        this.canvasImg.style.top = this.t + "px";
        this.canvasImg.style.left = this.l + "px";
        if (dh) {
            setTimeout(() => {
                this.canvasImg.style.setProperty("--img-time", "0s");
            }, 200);
        }
    }
    /*事件注册*/
    private canvasEventsInit() {
        this.box.onclick = () => {
            if (this.op.isMaskClose) this.close();
        };
        this.canvasImg.addEventListener("click", function (event: any) {
            // 只能阻止这个事件的传播
            event.stopPropagation();
        });
        let move = false;
        let dragging = false;
        // 按下的坐标v
        let pos = { x: 0, y: 0 };
        let moveDom = this.op.isMaskMove ? this.box : this.canvasImg;
        let wheelDom = this.op.isMaskWheel ? this.box : this.canvasImg;
        moveDom.onmousedown = function (evt: any) {
            move = false;
            dragging = true;
            // 记录按下的坐标
            pos = { x: evt.clientX, y: evt.clientY };
        };
        // 鼠标移动事件
        moveDom.onmousemove = (evt: any) => {
            move = true;
            //是否已经按下
            if (dragging) {
                const posl = { x: evt.clientX, y: evt.clientY };
                // 计算差值
                this.l += posl.x - pos.x;
                this.t += posl.y - pos.y;
                // 记录新的坐标
                pos = { x: evt.clientX, y: evt.clientY };
                this.upImgPosition();
            }
        };
        // 鼠标松开事件
        moveDom.onmouseup = (evt: any) => {
            dragging = false;
            if (!move) {
                // 没有移动，判定为点击
                if (this.op.isImgClose) this.close();
            }
        };
        //滚轮放大缩小
        wheelDom.onmousewheel = wheelDom.onwheel = (evt: any) => {
            var pos = { x: evt.clientX, y: evt.clientY };
            let roller = evt.wheelDelta ? evt.wheelDelta : evt.deltalY * -40; //获取当前鼠标的滚动情况
            var newPos = {
                x: (pos.x - this.l) / this.zoom,
                y: (pos.y - this.t) / this.zoom,
            };
            if (roller > 0) {
                // 放大
                this.zoom += 0.1;
                if (this.zoom > this.op.maxZoom) {
                    //最大的缩放级别
                    this.zoom = this.op.maxZoom;
                }
                this.l = (1 - this.zoom) * newPos.x + (pos.x - newPos.x);
                this.t = (1 - this.zoom) * newPos.y + (pos.y - newPos.y);
            } else {
                //  缩小
                this.zoom -= 0.1;
                if (this.zoom < this.op.minZoom) {
                    //最小的缩放级别
                    this.zoom = this.op.minZoom;
                }
                this.l = (1 - this.zoom) * newPos.x + (pos.x - newPos.x);
                this.t = (1 - this.zoom) * newPos.y + (pos.y - newPos.y);
            }
            this.tip();
            this.upImgPosition();
        };
    }
    // 添加操作按钮
    private addOperationButton() {
        const ele = this.createNode(`<div class="yyz-iv_operation">
        <div class="yyz-iv_operation-btn zoom-add">
            <svg t="1616925103431" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10151" width="20" height="20"><path d="M836 476H548V188c0-19.8-16.2-36-36-36s-36 16.2-36 36v288H188c-19.8 0-36 16.2-36 36s16.2 36 36 36h288v288c0 19.8 16.2 36 36 36s36-16.2 36-36V548h288c19.8 0 36-16.2 36-36s-16.2-36-36-36z" p-id="10152" fill="#ffffff"></path></svg>
        </div>
        <div class="yyz-iv_operation-btn zoom-sub">
            <svg t="1616925668114" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10948" width="20" height="20"><path d="M725.33 480H298.66c-17.67 0-32 14.33-32 32s14.33 32 32 32h426.67c17.67 0 32-14.33 32-32s-14.32-32-32-32z" p-id="10949" fill="#ffffff"></path></svg>
        </div>
        <div class="yyz-iv_operation-btn rotate-right">
            <svg t="1616925730136" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1951" width="20" height="20"><path d="M503.466667 285.866667L405.333333 226.133333c-8.533333-8.533333-12.8-21.333333-8.533333-29.866666 8.533333-8.533333 21.333333-12.8 29.866667-8.533334l145.066666 89.6c8.533333 4.266667 12.8 17.066667 8.533334 29.866667l-89.6 145.066667c-4.266667 8.533333-17.066667 12.8-29.866667 8.533333-8.533333-4.266667-12.8-17.066667-8.533333-29.866667l64-102.4c-123.733333 4.266667-226.133333 106.666667-226.133334 234.666667s106.666667 234.666667 234.666667 234.666667c85.333333 0 162.133333-46.933333 204.8-119.466667 4.266667-8.533333 17.066667-12.8 29.866667-8.533333 8.533333 4.266667 12.8 17.066667 8.533333 29.866666-51.2 85.333333-140.8 140.8-238.933333 140.8-153.6 0-277.333333-123.733333-277.333334-277.333333 0-145.066667 110.933333-264.533333 251.733334-277.333333z" p-id="1952" fill="#ffffff"></path></svg>
        </div>
        <div class="yyz-iv_operation-btn rotate-left">
            <svg t="1616925759280" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2144" width="20" height="20"><path d="M520.533333 285.866667c140.8 12.8 251.733333 132.266667 251.733334 277.333333 0 153.6-123.733333 277.333333-277.333334 277.333333-98.133333 0-192-55.466667-238.933333-140.8-4.266667-8.533333-4.266667-21.333333 8.533333-29.866666 8.533333-4.266667 21.333333-4.266667 29.866667 8.533333 42.666667 72.533333 119.466667 119.466667 204.8 119.466667 128 0 234.666667-106.666667 234.666667-234.666667s-98.133333-230.4-226.133334-234.666667l64 102.4c4.266667 8.533333 4.266667 21.333333-8.533333 29.866667-8.533333 4.266667-21.333333 4.266667-29.866667-8.533333l-89.6-145.066667c-4.266667-8.533333-4.266667-21.333333 8.533334-29.866667L597.333333 187.733333c8.533333-4.266667 21.333333-4.266667 29.866667 8.533334 4.266667 8.533333 4.266667 21.333333-8.533333 29.866666l-98.133334 59.733334z" p-id="2145" fill="#ffffff"></path></svg>
        </div>
    </div>`);
        ele.style.zIndex = this.op.zIndex + 1;
        ele.addEventListener("click", function (event: any) {
            event.stopPropagation();
        });
        ele.querySelector(".yyz-iv_operation-btn.zoom-add").onclick = () =>
            this.zoomAdd();
        ele.querySelector(".yyz-iv_operation-btn.zoom-sub").onclick = () =>
            this.zoomSub();
        ele.querySelector(".yyz-iv_operation-btn.rotate-right").onclick = () =>
            this.rotateRight();
        ele.querySelector(".yyz-iv_operation-btn.rotate-left").onclick = () =>
            this.rotateLeft();
        this.box.appendChild(ele);
    }

    tipDom: any;
    tipTime: any;
    // 提示
    private tip() {
        if (!this.op.tipTime) return;
        if (!this.tipDom) {
            this.tipDom = document.createElement("div");
            this.tipDom.className = "yyz-iv_tip";
        }
        if (this.tipTime) {
            // 还在显示
            clearTimeout(this.tipTime); // 关闭定时器
        } else {
            this.box.appendChild(this.tipDom); // 重新添加到页面上
        }
        this.tipDom.innerText = Math.round(this.zoom * 100) + "%";
        this.tipTime = setTimeout(() => {
            this.box.removeChild(this.tipDom);
            this.tipTime = null;
        }, this.op.tipTime);
    }
    // 左旋转
    rotateLeft() {
        this.rotate -= 90;
        this.upImgPosition(true);
    }
    // 右旋转
    rotateRight() {
        this.rotate += 90;
        this.upImgPosition(true);
    }
    // 放大
    zoomAdd() {
        this.zoom += 0.3;
        this.l -= (this.img_w * 0.3) / 4;
        this.t -= (this.img_h * 0.3) / 4;
        this.upImgPosition(true);
        this.tip();
    }
    // 缩小
    zoomSub() {
        this.zoom -= 0.3;
        this.l += (this.img_w * 0.3) / 4;
        this.t += (this.img_h * 0.3) / 4;
        this.upImgPosition(true);
        this.tip();
    }
    // 重置
    reset() {
        this.canvasImg.onload();
    }

    // 创建dom
    private createNode(htmlStr: string): any {
        var div = document.createElement("div");
        div.innerHTML = htmlStr.trim();
        return div.firstChild;
    }
}
